{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 导入数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# 导入数据\n",
    "import numpy as np\n",
    "import scipy.io as scio\n",
    "offline_data = scio.loadmat('offline_data_random.mat')\n",
    "online_data = scio.loadmat('online_data.mat')\n",
    "offline_location, offline_rss = offline_data['offline_location'], offline_data['offline_rss']\n",
    "trace, rss = online_data['trace'][0:1000, :], online_data['rss'][0:1000, :]\n",
    "del offline_data\n",
    "del online_data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 定位精度\n",
    "def accuracy(predictions, labels):\n",
    "    return np.mean(np.sqrt(np.sum((predictions - labels)**2, 1)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### knn回归"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 92 ms\n",
      "Wall time: 182 ms\n",
      "accuracy:  2.24421479398 m\n"
     ]
    }
   ],
   "source": [
    "# knn回归\n",
    "from sklearn import neighbors\n",
    "knn_reg = neighbors.KNeighborsRegressor(40, weights='uniform', metric='euclidean')\n",
    "%time knn_reg.fit(offline_rss, offline_location)\n",
    "%time predictions = knn_reg.predict(rss)\n",
    "acc = accuracy(predictions, trace)\n",
    "print \"accuracy: \", acc/100, \"m\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### knn分类"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 80 ms\n",
      "Wall time: 251 ms\n",
      "accuracy:  2.73213398632 m\n"
     ]
    }
   ],
   "source": [
    "# knn分类，需要把坐标转换成网格标号，预测后将网格标号转换为坐标\n",
    "labels = np.round(offline_location[:, 0]/100.0) * 100 + np.round(offline_location[:, 1]/100.0)\n",
    "from sklearn import neighbors\n",
    "knn_cls = neighbors.KNeighborsClassifier(n_neighbors=40, weights='uniform', metric='euclidean')\n",
    "%time knn_cls.fit(offline_rss, labels)\n",
    "%time predict_labels = knn_cls.predict(rss)\n",
    "x = np.floor(predict_labels/100.0)\n",
    "y = predict_labels - x * 100\n",
    "predictions = np.column_stack((x, y)) * 100\n",
    "acc = accuracy(predictions, trace)\n",
    "print \"accuracy: \", acc/100, 'm'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "#### 定位算法分析\n",
    "\n",
    "加入数据预处理和交叉验证"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# 预处理，标准化数据(其实RSS数据还算正常，不预处理应该也无所谓，特征选择什么的也都不需要)\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "standard_scaler = StandardScaler().fit(offline_rss)\n",
    "X_train = standard_scaler.transform(offline_rss)\n",
    "Y_train = offline_location\n",
    "X_test = standard_scaler.transform(rss)\n",
    "Y_test = trace"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# 交叉验证，在knn里用来选择最优的超参数k\n",
    "from sklearn.model_selection import GridSearchCV\n",
    "from sklearn import neighbors\n",
    "parameters = {'n_neighbors':range(1, 50)}\n",
    "knn_reg = neighbors.KNeighborsRegressor(weights='uniform', metric='euclidean')\n",
    "clf = GridSearchCV(knn_reg, parameters)\n",
    "clf.fit(offline_rss, offline_location)\n",
    "scores = clf.cv_results_['mean_test_score']\n",
    "k = np.argmax(scores) #选择score最大的k"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x580bf90>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 绘制超参数k与score的关系曲线\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "plt.plot(range(1, scores.shape[0] + 1), scores, '-o', linewidth=2.0)\n",
    "plt.xlabel(\"k\")\n",
    "plt.ylabel(\"score\")\n",
    "plt.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "accuracy:  2.22455511073 m\n"
     ]
    }
   ],
   "source": [
    "# 使用最优的k做knn回归\n",
    "knn_reg = neighbors.KNeighborsRegressor(n_neighbors=k, weights='uniform', metric='euclidean')\n",
    "predictions = knn_reg.fit(offline_rss, offline_location).predict(rss)\n",
    "acc = accuracy(predictions, trace)\n",
    "print \"accuracy: \", acc/100, \"m\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# 训练数据量与accuracy\n",
    "k = 29\n",
    "data_num = range(100, 30000, 300)\n",
    "acc = []\n",
    "for i in data_num:\n",
    "    knn_reg = neighbors.KNeighborsRegressor(n_neighbors=k, weights='uniform', metric='euclidean')\n",
    "    predictions = knn_reg.fit(offline_rss[:i, :], offline_location[:i, :]).predict(rss)\n",
    "    acc.append(accuracy(predictions, trace) / 100)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAY4AAAEKCAYAAAAFJbKyAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3XtclGX6P/DPw0lUEFRWMKDF0ESRw2gqrn0V1CTBY7ql\n/bbAbDO1PHRUs41W00rX43raDort18N3bS0VTF3XEctTKQqJlgdM8ECCoqCc5/n9MT4xjgMzo8zh\nuf28X6951czczFyXY1zd93Xfz0iyLIOIiMhSLo4OgIiI1IWFg4iIrMLCQUREVmHhICIiq7BwEBGR\nVVg4iIjIKjYvHDU1Na4ajSZz0KBBW4yf02q1sT4+Ptc1Gk2mRqPJnDVr1gxbx0NERPfHzdZvsGjR\nokkdO3bMKSkp8Tb1fO/evfds3rx5sK3jICKihmHTGUd+fn5Qenp6wosvvvipLMuSqTF1PU5ERM7J\npoVjypQpC+bOnfumi4uLztTzkiTJ+/bt+0N4ePjxhISE9JycnI62jIeIiO6fzZaqtm7dOrBVq1a/\najSaTK1WG2tqTOfOnY/k5eUFu7u7V6WmpiYNHjx48+nTp9saj5MkiddFISK6BzZZ1ZFl2Sa3adOm\nzQ4KCsoLCQnJDQgIuNSkSZObzz333Jq6xut0OqlFixZFRUVFLYyf04cprvfee8/RIdiUyPmJnJss\nMz+1u/27s8F/v9tsqWr27NnT8/LygnNzc9usX79+ZJ8+ff67Zs2a5w3HFBQU+Mu3q+GWLVsGNW7c\nuKxFixZXbRWTszp37pyjQ7ApkfMTOTeA+ZFpNt9VpVCWm1auXDkWAMaOHbty48aNI5YvXz7Ozc2t\nOjIyMuvrr78eYq94iIjo3kiyCi6rLkmSrIY475VWq0VsbKyjw7AZkfMTOTeA+amdJEk26XGwcBAR\nCcpWhYOXHHECWq3W0SHYlMj5iZwbwPzINBYOIiKyCpeqiIgExaUqIiJyCiwcTkD0dVaR8xM5N4D5\nkWksHEREZBX2OIiIBMUeBxEROQUWDicg+jqryPmJnBvA/Mg0Fg4iIrIKexxERIJij4OIiJwCC4cT\nEH2dVeT8RM4NYH5kGgsHERFZhT0OIiJBscdBREROgYXDCYi+zipyfiLnBjA/Mo2Fg4iIrMIeBxGR\noNjjICIip8DC4QREX2cVOT+RcwOYH5nGwkFERFZhj4OISFDscRARkVNg4XACoq+zipyfyLkBzI9M\nY+EgIiKrsMdBRCQo9jiIiMgpsHA4AdHXWUXOT+TcAOZHprFwEBGRVdjjICISFHscRETkFFRTOGJj\nUxAfPwNpaRmODqXBib7OKnJ+IucGMD8yzc3RAVhqz54UAMCZM+8AABITezkwGiKiB5fNexw1NTWu\njz322A9BQUH5W7ZsGWT8/LRp0+akpaUlNmnS5Nbq1auTw8LCTt4VpCTJQG2c8fHv4ptvZto0biIi\ntVNtj2PRokWTOnbsmKP/5X+n9PT0hGPHjkVlZWVFLlq0aFJycvJqS16zvNy1weMkIiLL2LRw5Ofn\nB6Wnpye8+OKLn5qqeps3bx6clJSUCgDdu3c/WFxc7FtQUOBv7nU9PWtsEa7DiL7OKnJ+IucGMD8y\nzaaFY8qUKQvmzp37pouLi87U8xcuXAgMDg7OU+4HBQXl5+fnB9X3mqGh0/Hqq080dKhERGQhmxWO\nrVu3DmzVqtWvGo0ms741NuPnTC1p6UUjOLg3une/hFOnjtzxfwparVbV95XHnCUe5mf5/djYWKeK\nh/k92PlptVokJycjOTkZKSkpsBWbNcenT58++4svvnjOzc2tury83PPGjRvNhg8f/uWaNWueV8a8\n/PLLK2JjY7UjR45cDwBhYWEn9+zZ09vf37/gjiBvN8cPHgS6dbNJuEREwlFdc3z27NnT8/LygnNz\nc9usX79+ZJ8+ff5rWDQAYPDgwZuVxw4cOBDj6+tbbFw0DFVX2ypaxzL8vwcRiZyfyLkBzI9Ms9s5\nDmUJauXKlWMBYOzYsSsTEhLSMzIyekVERGQ3bdr05qpVq0bX9xpVVfaIlIiI6qOaa1UBMnbuBPr1\nc3Q0RETqoLqlKlsQdamKiEhNVFU4RF2qEn2dVeT8RM4NYH5kGgsHERFZRVU9jg0bgKefdnQ0RETq\nwB4HOOMgInIGLBxOQPR1VpHzEzk3gPmRaaoqHNxVRUTkeKrqcSxbBowb5+hoiIjUgT0OiLtURUSk\nJqoqHKIuVYm+zipyfiLnBjA/Mk1VhYMzDiIix1NVj2PmTGDGDEdHQ0SkDuxxQNylKiIiNVFV4RB1\nqUr0dVaR8xM5N4D5kWksHEREZBVV9TimTAHmz3d0NERE6sAeBzjjICJyBiwcTkD0dVaR8xM5N4D5\nkWmqKhzcVUVE5Hiq6nE8/zyQmuroaIiI1IE9Doi7VEVEpCYsHE5A9HVWkfMTOTeA+ZFpqioc7HEQ\nETmeqnociYnA1q2OjoaISB3Y44C4S1VERGqiqsIh6lKV6OusIucncm4A8yPTVFU4OOMgInI8VfU4\nYmKA/fsdHQ0RkTqwxwFxl6qIiNREVYVD1KUq0ddZRc5P5NwA5kemsXAQEZFV6u1xlJSUeK9bt27U\nkSNHOv/000/tJUmSH3300Z87d+58ZNSoUeu8vb1L7BLk7R7Ho48CP/1kj3ckIlI/W/U46iwcEyZM\nWHr48OEugwYN2tKhQ4cTjzzyyFlZlqWzZ88+cuLEiQ5bt24d+Nhjj/3w97///ZWGDuquIG8XjjZt\ngLNnbf1uRERisHvhOHToULdu3bodqu+HLRnTEJTCERQE5OXZ+t3sT6vVIjY21tFh2IzI+YmcG8D8\n1M7uu6osKQj2KBqGuKuKiMjxzJ7jyMjI6DV37tw39+/f36OioqIRoJ8B3Lhxo5ldIkTtjKNlS6Cw\n0F7vSkSkbg47xzF58uSFb7zxxryLFy8+VFJS4l1SUuJtSdEoLy/37N69+8Ho6OijMTExBxYsWDDF\neIxWq4318fG5rtFoMjUaTeasWbNm1Pea3FVFROR4ZguHj4/P9c6dOx/x8PCotOaFPT09y3fv3h13\n9OjR6D179vT+7LPPxpw+fbqt8bjevXvvyczM1GRmZmpmzJgxq77XFHWpSvS95CLnJ3JuAPMj09zM\nDVi+fPm4AQMGbOvTp89/fXx8rgP6paPXXnttvrmfbdKkyS0AKC0t9aqurnZr1KhRhfEYa6ZRnHEQ\nETme2RnHjBkzZnl6epbX1NS4lpaWepWWlnqVlJR4W/LiOp3OJSoq6pi/v3/BK6+88vfg4OA79kRJ\nkiTv27fvD+Hh4ccTEhLSc3JyOtb3elVVgAourWU1kXd1AGLnJ3JuAPMj08zOOLKzsyNOnjwZpm9Q\nW8fFxUV37NixqHPnzoUkJCSk9+zZ8zuNRpOpPN+5c+cjeXl5we7u7lWpqalJgwcP3mxqOUsvGUAI\nUlKA5s19ER0d/duHrkw3eZ/3eZ/3H+T7Wq0Wq1evBgCEhITAVszuqnr33Xdntm3b9vTIkSPXm1pq\nstQbb7wxLygoKH/y5MkLTT0vy7Lk5+dXeOrUqXYtWrS4ekeQkiR7eMiorATKygBPz3uNwjlpBd9L\nLnJ+IucGMD+1c9iuqgULFkwZPXr0Km9v7xLl1qxZsxvmfq6wsNCvuLjYFwCKiopabtu2bUBERES2\n4ZiCggJ/JaktW7YMaty4cZlx0VC4u+v/yT4HEZFj2ez7OLKzsyOSkpJSa2pqXAMCAi4//fTT/zdm\nzJjPVq5cORYAxo4du3Lp0qUTli9fPs7Nza06MjIya9KkSYu6dOly+K4gJUn28ZFx/Tpw9SrQvLlN\nQiYiEordLzly4sSJDh06dDhR3w9bMqYhSJIk+/nJKCwECgqAVq1s/Y5EROpn96WqOXPmTOvTp89/\nly1bNn737t1xubm5bc6cORO6a9euvkuXLp0QFxe3e86cOdMaOqC6iLxUpTS3RCVyfiLnBjA/Mq3O\nXVVr1qx5vqCgwH/16tXJ//jHP146depUOwBo167dqejo6KPr168f6e/vX2C3QG9HKuohQCIitVDN\nd44/8oiMs2eBU6eAtnVs2CUioloP/HeOi7xURUSkJqopHCIvVYm+zipyfiLnBjA/Mk01heP8+RkA\nUvDSSzOQlpbh6HCIiB5YZnscTz311L/HjBnz2YABA7a5uLjo7BTXHZTv41CEhr6DRYvikZjYyxHh\nEBGpgsN6HOPGjVv+v//7v/+vbdu2p6dOnfrhTz/91L6hg7DWmTMfYMmSnY4Og4jogWS2cDzxxBM7\n165d++yRI0c6h4SEnOvbt++uP/zhD/tWrVo1uqqqyt0eQZpSXu7qqLducKKvs4qcn8i5AcyPTLOo\nx1FUVNRy9erVyZ9++umLnTt3PjJx4sTF+/fv7zF06NCvbB1gXTw9axz11kREDzSzPY5hw4ZtOnny\nZNhzzz33xejRo1e1bt36kvJc165dv//++++72jzIu3oc07Fo0ZPscRAR1cPu16pS7N69Oy4uLm53\nQ7+xNSRJklu3noFLl1wREVGDOXOeYNEgIjLDYc3x48ePh1+7du2369Feu3at+bJly8Y3dCDmJCbO\nBJCCV16ZKVzREH2dVeT8RM4NYH5kmtnC8cknn/y5efPm15T7zZs3v/aPf/zjJduGdbfGjfX/vHXL\n3u9MRESGzBaOGzduNDOccVy9erWF4X17adJE/8+yMnu/s+2J/A1kgNj5iZwbwPzINLPfOT58+PAv\nn3nmmQ0vvPDC57IsS6tWrRo9YsSIjfYIzpAy4xCxcBARqYnZGcdHH3309rBhwzb961//+uOXX345\nfPjw4V9+/PHHb9kjOEMiFw7R11lFzk/k3ADmR6aZnXG4urrWjBs3bvm4ceOW2yOgurDHQUTkHMxu\nxz1z5kzo22+//VFOTk7HsrKyxoB+e+zZs2cfsUuEt9/v009lvPgiMHo08Pnn9npnIiL1cth23L/+\n9a9/efrpp//Pzc2tetOmTcMSEhLSX3rppX80dCDmiLxURUSkJmYLR1ZWVuTTTz/9f5IkyeHh4ccX\nLlw4ed26daPsEZwhkZeqRF9nFTk/kXMDmB+ZZrbH0bhx47KamhrX3r1775k9e/b0Nm3a5Hp5eZXa\nI7g749D/kzMOIiLHMtvj+P7777uGhYWdLCsra7xs2bLxFy5cCHz11VeXREZGZtkpRkiSJO/ZI6N3\nb+Dxx4G9e+31zkRE6uWQa1XV1NS4Tp069cO5c+e+2dBvbA1JkuRDh2R06wZ06QL88IMjoyEiUgeH\nNMddXV1rMjIyepWUlHg39Btbiz0O9RI5P5FzA5gfmWa2x9GzZ8/vBg0atGXEiBEblUuqS5IkP/XU\nU/+2fXi12OMgInIOZnscycnJqwHlOzFqrVq1arTtwrqTJEnyxYsyHnoI8PcHLl+21zsTEamXw76P\nwxlIkiRfuyajeXPA2xu4ccPREREROT9bFQ6zS1WjR49eZRSIDACff/75Cw0dTH1EXqrSarVCX6VT\n5PxEzg1gfmSa2cKRmJiYphSLoqKilhs2bHimS5cuh20f2p08PAAXF6C6Wn9zMxs5ERHZgtVLVTdv\n3mzap0+f/x48eLC7jWK6iyRJsizL8PICbt7UL1V5O3yfFxGRc3PYtaqMZWVlRep0Oqt/riGIvCWX\niEgtzBYALy+vUm9v7xJvb+8SX1/f4nfeeeeDOXPmTLNHcMZE7XOIvpdc5PxEzg1gfmSa2U5BaWmp\nlz0CsYTIXx9LRKQWZnscmzZtGhYXF7fb19e3GACKi4t9tVpt7NChQ7+yS4So7XFoNMDRo/pLjnTp\nYq93JyJSJ4f1OFJSUlKUogEAvr6+xSkpKSkNHYglRF2qIiJSE7OFo6SkxPvWrVtNlPu3bt1qUlxc\n7Gvu58rLyz27d+9+MDo6+mhMTMyBBQsWTDE1btq0aXMiIyOzYmJiDpw8eTKsrtdLS8vAyZMzAKRg\n8uQZSEvLMBeCaoi+zipyfiLnBjA/Ms1sj6N37957xo8fv+zll19eIcuytGLFipdjY2O15n7O09Oz\nfPfu3XFNmjS5VVFR0ahLly6HBw0atKVt27anlTHp6ekJx44di8rKyoo8ePBg9+Tk5NUHDhyIMfV6\nkyZtx7VrHwAADh8GJk16BwCQmNjLwlSJiKghmO1xlJaWes2cOfPdXbt29QWAJ554YueMGTNmNW3a\n9Kalb1JUVNSyZ8+e3+3cufOJ4ODgPOXxl19+eUVcXNzuZ555ZgMAhIWFndyzZ09vf3//gjuClCQZ\nuDvO+Ph38c03My0Ng4jogeKwS454eXmVfvTRR2/fy4vrdDoXjUaTefz48fCFCxdONiwaAHDhwoVA\nw8eCgoLy8/Pzg4wLR13Ky13vJSwiIroPZgtHv379/rNx48YRSoP86tWrLUaNGrVu+/bt8eZ+1sXF\nRXfs2LGoc+fOhSQkJKT37NnzO41Gk2k4xrgaGl+Ft1YygJDb/+4LIBqenjUAatcplWvOqO3+woUL\nER0d7TTxMD/L7xuukTtDPMzvwc5Pq9Vi9erVAICQkBDYjCzL9d46dux43JLHzN1ef/31eQsWLJhs\n+NjYsWNXrFu3bqRyv3379icvX77sb/yzAOTQ0OkyIP92Cw2dJm/dukcWwe7dux0dgk2JnJ/Iucky\n81M7/a94635XW3Izu6tKkiT58OHDv52a+OGHHx6TLVgzKyws9FN2XxUVFbXctm3bgIiIiGzDMYMH\nD968Zs2a5wHgwIEDMb6+vsV1LVMtWhSPnj3fBZCCJk3exaJFTwrTGFf+z0FUIucncm4A8yPTzC5V\nzZs37434+PjtyhVxDx8+3OWf//znn8z93KVLl1onJSWl1tTUuAYEBFx+7bXX5vft23fXypUrxwLA\n2LFjVyYkJKRnZGT0ioiIyG7atOnN+r4cKjGxF+LieqFpU6CqCnjySWvSJCKihmLR1XGvXLnyuwMH\nDsRIkiTHxMQc8PPzK7RDbL9RTo6npWXgqad2oLLSDb16VeOtt/oLMevQCv6dACLnJ3JuAPNTO4ft\nqgIANze36latWv1aUVHRKCcnpyMA9OrVy64n8NLSMjBp0nZUVurPcmRkABcu8CwHEZG9mZ1x/Otf\n//rjG2+8Me/GjRvNQkJCzh07diyqX79+/9mxY0d/O8UISZLk/v3fwY4ds+56jmc5iIhMc9i1qpYv\nXz4uOzs7IigoKD8zM1Ozd+/e//Hx8bne0IGYU1FhenLEsxxERPZltnBcv37dp1mzZjdatWr169Wr\nV1v07Nnzux9//LGTPYIz1KhRtcnHlbMcama4l1xEIucncm4A8yPTzBaOhx9++Py1a9eajxgxYmNs\nbKy2b9++u3r06LHfHsEZmjixP0JD37njsdDQ6Xj11SfsHQoR0QPNqu8cP3v27CMXL1586PHHH//W\nhjHdxXBX1ezZO7Fvnyu8vGqwfv0TbIwTEdXBVj0OqwqHoyiFAwB+/RXw9wdatACKihwcGBGRE3NY\nc9zZ+PkBbm7A1atAebmjo2kYoq+zipyfyLkBzI9MU13hcHEBWrfW//ulS46NhYjoQaS6pSoAiIkB\nDh4Evv0W6NnTgYERETkxh54cdzaSlAFgB156yQ1BQdWYOFGMS48QEamB6paq0tIykJOzHcAs5OSk\nYMeOWZg0abuqv4Nc9HVWkfMTOTeA+ZFpqiscixfvwI0bH9zx2JkzH2DJkp0OioiI6MGiusIh4qVH\nRL46JyB2fiLnBjA/Mk11hUPkS48QEamB6gpH7aVHMgDMAJCCxo2fQUxMawdHdu9EX2cVOT+RcwOY\nH5mmusKRmNgLf/pTIFxd1wKYBSAFZWUb8M9/XlB1g5yISC1UeY4jPn4Gv5uDiMgMnuMwUNsg15/n\n0KdRjfz8K44LiojoAaG6pSpAaZBnANCf5wBSAMzC2bOSKperRF9nFTk/kXMDmB+ZpsrCMXFifzRu\nvBTAnec5yspW8DwHEZGNqbLHAQCRkVOQnb0AxstV4eFX8OOPKx0QJRGRc+Fl1Y20bt0UtctV/QFU\nA3DDiRO/IiVlmUNjIyISmWoLR+1yVTwMi4dOF4WZM3eqqniIvs4qcn4i5wYwPzJNtYUjMbEX2rZ9\nCPplKqV46BvlOt0mfPxxliob5UREzk61PQ5AOc+h723oi4bx8zzXQUQPLp7jMGHixP7Yu3cpyso6\n3H6E5zqIiGxNtUtVgH656q23esPF5RjUfK5D9HVWkfMTOTeA+ZFpqp5xAEBKyngAwMyZC6DTbYLh\nrKOszA9/+csX/HZAIqIGpOoehyH9uY5h0M86ag8GenqOw8aNo1g8iOiBw3McZujPdexAbdHQX3a9\nvNwfSUlLVbFkRUSkBsIUjokT+8PTM+/2vTv7HUVFG5z6e8lFX2cVOT+RcwOYH5kmTOFITOyFDh28\nbt8znnm8iDNnjmLgwLnw9v5/6Nx5gtMWESIiZydMjwMA0tIyMGnSdpw54w79zqplALQAvAEEQH9Q\nUN849/D4EdOm9fmtuU5EJBr2OCyQmNgLixbFo2XLE9DPNPYAeBRAaxhfmqSyspPqLk1CROQMbFY4\n8vLyguPi4naHh4cfj42N1a5evTrZeIxWq4318fG5rtFoMjUaTeasWbNm3O/7Jib2QmrqhNvXseoA\n/Y5jN9x5aRLnuq6V6OusIucncm4A8yPTbHaOw93dvWrBggVToqOjjxYWFvp16tTpx+7dux/s0KHD\nCcNxvXv33rN58+bBDfne+utYbUJ2drXBo8bFQ79spdO1wvvvb8Ts2Zsgy03g6emFdu18MXPmM9zC\nS0Rkgs1mHAEBAZejo6OPAoCfn19h165dv7948eJDxuNssf4GKNtz+wO4dPt2AnXNPIA2qKrqhurq\n11Fa2gaZmb/DU08ttttMJDY21i7v4ygi5ydybgDzI9Ps0uM4ffp02+PHj4fHxMQcMHxckiR53759\nfwgPDz+ekJCQnpOT07Gh3nPixP4IDd0OIAn6NK8AOIra4vHB7X+2xt09kHxUVrrh/fc3o0mTwYiM\nnIL4+BnciUVEBDvsqiotLfWKjY3VvvvuuzOHDBnyteFzJSUl3q6urjXu7u5VqampSR9++OHU06dP\nt70rSEmSk5KSEBISAgDw9fVFdHT0b/+3oKxTGt+/edMFS5bsxOXLefDw0KFt29bYsOFn6HQ+AJKh\n33EFAOcA1AD4M4BUABUA/ACUA3gWwCcAiuHiAgQHt8bvfleG4cMfw9Spk+p9f0vvL1y40KJ81Hpf\n5PwM18idIR7m92Dnp9VqsXr1agBASEgI3n//fZus6ti0cFRVVbkPHDhw64ABA7ZNnjx5YX1jZVmW\n/Pz8Ck+dOtWuRYsWV+8I0sLtuJZISVmGmTN33r6ulWEvXrk8O6CfdSwFMAG1/RDln2sAlMLFRYeQ\nEE8sXvziffdCtFrtb38JRCRyfiLnBjA/tbPVdlybFQ5ZlqWkpKRUPz+/wvnz579makxBQYF/q1at\nfpUkSd68efPg8ePHL8vPzw+6K8gGLByAvnh8/HEWysqehX6GAQCl0O/CApSvoa39no8Z0BeTVOjP\ng9ReCysg4DV8+ulQNtKJyOmornB8++23j/fq1SsjMjIyS5IkGQBmz549/fz58w8DwNixY1cuXbp0\nwvLly8e5ublVR0ZGZk2aNGlRly5dDt8VZAMXDkB/WHDJkp3Iz/8V58/no7y8FFVVzQF0Qm3RcIP+\nIGEKamcjs6A/I7IG+qa7G1xd3REZ6X/HTqy0tAy8++4a/PzzJZSVVUCnk+Hi0hRNmnhz1xYR2YXq\nCkdDskXhMCUlZRnmzNGislKCfplqKYAN0M84lJ3LfVA7S1FOo+uXr4BieHhUQZarUVXVEkBzg1e/\n++T68OGhKCpyR0FBPvz9gzBxYn8hi4nIywEi5wYwP7XjyXE7SEkZj3//+xU88kgNJCkVQG8AL0O/\nTHUC+lmH8U6sVAD+AMYDCERlZQiqqgIAdDQYZ7hraxaAPqislLFu3RXs2NEfx45dwY4dmRg4cC4a\nNx7Ja2kRkVPjjKMOhktZBQXXIUk3ceWKO/TXvWpze5Th8pVxo92Y0i/JgL7YlEI/q6l79tK4sQfa\ntg1F69ZNhZ2NEJHtcKnKCeJMS8vAqFHzUVLS6fYjSoFIuX1TGJ5YVyj9khkG9w3HGTbfjXdxXQJQ\nBklqikaNZLi7eyAk5PcsKERULy5VOYHExF5Yt+41BAQYnkZXfvlXG9wMT6wbjgVqr51VbfDv+ahd\nAlMOJirLYDL0xaQHZHkAysuDUFIyGdnZTbFjhxv++MelDr/WljmGe+VFI3JuAPMj01g4rJSY2Auf\nfpqEzp1d0KjRFQA5AN7BncXC8MR6AYBc6IvDC7izuCiFpwa1RQSoPd1u3CPZA/2BxNrLpZSV+eL9\n9zfCw+MJuLr2g6vrYH7nCBHZFJeq7lNaWgb+8pcvkJtbisrKW9DpyiHLEqqrG8HT0wuPPuqLv/5V\nv/VWGZudfQNVVW0BBKL2+0JKAbRDbb/EuE9ieLakP2qXslINxhj2SfTLWwDg4uIFDw8dl7iIHjDs\ncaggTkuZKjbV1eW3t/B2gP6X/1LoC4nCcHnL8GCiIaVPYqjungmgLyo8W0IkJhYOFcR5r5S95IYF\n5datK6ioaIbasyDKLizle0ZScGdDHjDdlDc++W7I9DkUFxd3VFZWQ6e7+8/cxaUpPDx0kKRKyLKL\nReNqaopRXd3srnGGY1xdm8HdvSlCQrxUVcBEPwfA/NTNVoXDZt/HQdZLTOx1xy9MpZD89NMl3LxZ\nDGA19GdLdt4eYVwo6vo4DXsmhgx3cj0PIBWVlfVFGACdLh7l5cYFyNw4NxPvbTimtoBdu3YOAwem\n3B6j//tuSbHiqXwi++GMQ0WUsyUnTpxEfn4z6HRJuHMWofRJDNXVMwHqPodSl4YcZzjG1GxIoRSV\n+oqVcv0w5VIwub89w4JCDzIuVakgTnsyvtZWVVUNystLAbSC6UudGPdMgLrPodSlIccZjjG1xKaw\ntAgpBysN3b1ZQDkLY+lSGzcUkJpxqUpg97LOaryspTBc3iorK4dOdw4uLtlwdS1FVVUV7iwqhjOU\n+n55G7oIb9uTAAARAElEQVSXcb8A+H09Y8z9NbTkr2l9S3GAvogEQJatWWrbjvLyeGRnr0F29s/Y\nsWPf7edrl9Dc3K7A1dX7jiIk0ixH9B6A6PnZCguHYOoqKICpolIOoAr6cyjmloNwH+OKAHjUM8bU\nEpshS4qVqb/KxsVEmb0YFxhjyjjDHAKMxuiLS2Xlh0avp3+8tHQNMjP1/Zq6ZjkiFRh6sHCp6gFX\n1zkU87ulqu57nDJGpytBZaXx1YQVlvY4TM3GjYtJCqxbaruXJTTjfk1d8Rsvo0lwd5fh5lZl8W41\na8cBTexWqJSvFTh3rhSVlWXQ6cogyy6/nW8yjCEtLQOLF+9ARYUbGjWq5pJgA2KPQwVx0r27ezZU\n+3lbWqwAH9S9FAdY39yvb0KeAtNFyLjYWFJgLCmO9zvu/vs9lo7T6W6gstIP+m3jhodcTW1iqADw\nKPRf5WxdbHXFxZlcLRYOFcR5r0RfZ7VXfqaX4gw3C1j7i9fUhgKFUhCM+zeWznIMC4w9drVZOhMy\nVgHgJQvGGb6eUrCVr2BW/gxNbWIwvkq0pbFZOpMzV4SuQfn7Yem273ud8VmyhbyhZ19sjhOZYaq/\nc2cx+QVAtgWzl/o2FCiUHs2HuLN/Y6pfU9fVkuu7X5d7HXev/Z5+Jn7WFMPXU957B2q/jrmuOEyd\nMbIktrrGWLshotHt17DkjNK9nmOqe0xp6Q5kZl7BwIEpcHWtQk1NOxjOvnbs2HdH4XN1bQZZrvpt\n6c9RsywWDicg8mwDcGx+9W0WsETdS2j64uLh4QJJyjcoQsqGA6XY1LWhwLjA2HJXG2D6P3VL/vOP\nhX6pyRLK6xnuljMXR7WJxyyNrSE2RLS2cJylYywdZ3y9uTaoqSmFvmjUVfgCULv052fwWncXIU9P\nHzRu3MxMnPeOhYOoHvdSeCyb5RgWGFvvagMsnwmZYu045f/6jZeh3sHdmxiMl7OseU9LZnJ1PWbK\nvRarexm3A/p+j2GBMTf7Uv6sHjV6LeMi1APl5R+gvBzQz1waHnscToA9DvW6n9wMC0xFhSvc3Goa\nZLeaqXF3Hw61ZY9D+ffF0G9YSALwBfQ9h1sAfI3iMGygWxpbXWOs3RCh9KisvdrB/Y5TvtgtxeAx\nU7MvwzF1zc6ML3o6y+A59jiIhHK/y2jWurd+zzW4uMyzuC+kH5cPV9ef4O7eFM2b34Sv7wZ4ewfC\n0zMAr776BAAYxdHk9s9dv/36lsRm+H51zeQA87M05YyRJbO5hpwZlt7+p/G3gNY3+zK19Kc8bvhP\n2+OMg4iEYtyXqi1MDXf26P5fy3AbsmFPo77Zl6kdaLj9+AbYc8bBwkFE5ACmrjdXXd3oriVLpfDp\ndCWoqmoLWTZe+qsA0B61RUg5LwOwcKggznslcg8AEDs/kXMDmJ+zUYpNebkrPD1r8OqrT/x2/sOw\nCMlyY7i7N8W1a2vY4yAiepDV1Rer63FJ4q4qR4dBRKQqtjo57tLQL0hERGJj4XACWq3W0SHYlMj5\niZwbwPzINBYOIiKyCnscRESCYo+DiIicAguHExB9nVXk/ETODWB+ZBoLBxERWYU9DiIiQbHHQURE\nToGFwwmIvs4qcn4i5wYwPzLNZoUjLy8vOC4ubnd4ePjx2NhY7erVq5NNjZs2bdqcyMjIrJiYmAMn\nT54Ms1U8zuzo0aOODsGmRM5P5NwA5kem2ewih+7u7lULFiyYEh0dfbSwsNCvU6dOP3bv3v1ghw4d\nTihj0tPTE44dOxaVlZUVefDgwe7JycmrDxw4EGOrmJxVcXGxo0OwKZHzEzk3gPmRaTabcQQEBFyO\njo4+CgB+fn6FXbt2/f7ixYsPGY7ZvHnz4KSkpFQA6N69+8Hi4mLfgoICf1vFRERE988uPY7Tp0+3\nPX78eHhMTMwBw8cvXLgQGBwcnKfcDwoKys/Pzw+yR0zO5Ny5c44OwaZEzk/k3ADmR3WQZdmmt5KS\nEq8uXbr88NVXXw0xfm7gwIFbvv32257K/b59+/7n8OHDnY3HAZB544033niz/maL3+s2/SKnqqoq\n9+HDh3/5pz/96Z9Dhgz52vj5wMDAC3l5ecHK/fz8/KDAwMALxuNssQ+ZiIjujc2WqmRZlsaMGfNZ\neHj48cmTJy80NWbw4MGb16xZ8zwAHDhwIMbX17fY39+/wFYxERHR/bPZyfFvv/328V69emVERkZm\nSZIkA8Ds2bOnnz9//mEAGDt27EoAmDp16odpaWmJTZs2vblq1arRhruuiIjICdm6x3E/tz179vTS\naDRHIiIishYvXvyqo+Ox9Pb73//+XERERFZ0dHRm165dD8myjBs3bngPGTLkq4iIiKyhQ4duKikp\n8VLGL1q0aGJERESWRqM5snfv3seVx3Nycjp069btYERERNb06dM/cFQ+o0eP/rxVq1YFnTp1ylYe\na8h8Kisr3V944YXPIiIisvr06bPr0qVLAY7O77333ksJDAzMj46OzoyOjs5MT08foNb8zp8/Hxwb\nG7u7Y8eOx3v37q1dtWpVsiifYV25ifL5lZWVeXbr1u1gVFTU0e7dux+YP3/+FGf47Oz2l9faW3V1\ntWtoaOjp3NzckMrKSveoqKijOTk5HRwdlyW3kJCQ3KKiohaGj7355psff/TRR2/JsowPP/zw7bff\nfvtDWZZx/PjxjlFRUUcrKyvdc3NzQ0JDQ0/rdDpJlmV07dr10MGDB7vJsowBAwakb9u27UlH5JOR\nkfE/R44c0Rj+Ym3IfJYuXTp+3Lhxy2RZxvr165955pln1js6v5SUlPf+9re/vWY8Vo35Xbp0KSAz\nMzNalmVcuXLFz9/f/3JOTk4HET7DunIT6fO7efNmE1mWUV5e3ig8PPzHn3/+uZ2jPzu7JW/tbd++\nfT3i4+O/Ue7PmTNn6pw5c6Y6Oi5LbiEhIbmFhYUtDR9r3779ycuXL/vLsv4ve/v27U/KsozZs2dP\n+/DDD99WxsXHx3+zf//+mIsXL7YOCws7oTy+bt26kWPHjl3hqJxyc3NDDH+xNmQ+8fHx3xw4cKC7\nLMuoqqpy8/Pzu+Lo/FJSUt6bN2/e68bj1Jqf4W3gwIFbdu7c2U+0z9AwNxE/v8LCwpZhYWEnfvnl\nl4cd/dk57bWqTJ3xuHDhQqAjY7KUJElynz59/qvRaDI/+eSTPwNAQUGBv9L49/f3L1AOOl68ePGh\noKCgfOVnlTyNHw8MDLzgTPk3ZD6Gn7Wbm1u1j4/P9atXr7awb0Z3W7JkyasdO3bMGTNmzGfFxcW+\ngPrzMzxTJdpnqOTWo0eP/YA4n59Op3OJioo65u/vXzBhwoSlDz/88HlHf3ZOWziUhroafffddz2P\nHTsWtXbt2mdnz549fe/evf9j+LwkSbKa8zMmWj4AMG7cuOW5ublt9u/f38PV1bXm9ddf/5ujY7pf\npaWlXiNHjly/YMGCKV5eXqWGz6n9MzTMrWnTpjdF+vxcXFx0x44dizp9+nTbZcuWjc/MzNQYPu+I\nz85pC4fxGY+8vLxgw4rpzFq3bn0JADp06HBi2LBhmw4dOtTN39+/4PLlywEAcOnSpdatWrX6FTB9\nliUoKCg/MDDwguEp+rrOuDhKQ+SjfJ6BgYEXlN121dXVbtevX/dp0aLFVftmdKdWrVr9KkmS7OPj\nc33ChAlLDx061E2JVY35mTpTJcpnaCo30T4/AAgJCTmXkJCQvmfPnt6O/uyctnA89thjP5w6dard\nuXPnQiorKz02bNjwzODBgzc7Oi5zbt261aSkpMQbAK5cufK79PT0hIiIiOzBgwdvTk1NTQKA1NTU\npKFDh34F6M+yrF+/fmRlZaVHbm5um1OnTrXr1q3boYCAgMvNmjW7cfDgwe6yLEtffPHFc8rPOIOG\nyEf5j9zwtTZu3Diib9++uxyXmd6lS5daA/r/kNauXftsRERENqDO/OQ6zlSJ8BnWlZson19hYaGf\nssxWVFTUctu2bQMa6vfJfeXniCaPpTetVts7Ojo6s1OnTtmLFi2a6Oh4LLmdPXu2TVRU1NGoqKij\nffr02bVixYqxslz/9rmFCxdO6tSpU3Z0dHRmRkbG/yiPHz9+vGO3bt0OdurUKXvq1KlzHJXTyJEj\n17Vu3fqih4dHRVBQUN7nn38+uiHzqaysdB89evTnnTp1yo6Li/uvvberKvm5u7tXBgUF5X322Wcv\nPPfcc2siIiKyunTp8sOUKVPmK41INea3d+/exyVJ0kVFRR1Vtqdu27btSRE+Q1O5paenDxDl88vK\nyorQaDRHIiMjj/Xv33/7p59+OkaWG/b3yb3kp4qvjiUiIufhtEtVRETknFg4iIjIKiwcRERkFRYO\nIiKyCgsHCSUlJSXlb3/72+v1jfn666+HnDhxooO9YqrPuXPnQpStokRqwcJBQrHkBO2mTZuG5eTk\ndLRHPLZWU1Pj6ugY6MHDwkGqN3v27OkPP/zw+ccff/xb5QQsAHzyySd/7tat26EuXbocfuuttz4u\nKytrvG/fvj9s2bJl0Jtvvjm3c+fOR86ePfuIqXHG75GSkpIybty45XFxcbsjIyOz1q9fPxK4e8Yw\nb968N95///33ACA2NlY7Y8aMWdHR0Uc1Gk3m6dOn244YMWJjp06dflyxYsXLys/odDqXMWPGfNam\nTZvcP/7xj/8qLy/3BIDDhw93iYmJORAWFnayf//+OwoLC/2U133nnXc+eOyxx35YvHjxRNv9yRLV\nwZ4HkXjjraFvV65c8WvXrt3Ply5dCvjll18eDgwMzFcup214afvx48cvXbJkySuyLCM5OXnVl19+\n+ZTyXF3jDG/vvfdeSkRERNa1a9d8z58/HxwaGnpalu++qu68efNef//99/8iyzJiY2N3v/jii5/U\n1NS4pKSkvNe8efOrp0+fDi0pKfEKDg4+r9PppNzc3BBJknT//ve/h5WXlzd66qmnvty4cePwyspK\n94iIiKy8vLwgWdZf+lq56mlsbOzuUaNGra2oqPBw9J8/bw/mzabfOU5ka9u3b49/8sknvwkICLgM\nAP369fuPfPs76s+ePfvIxIkTF2dmZmrKysoaywbfXW/478bjdDrdXTNxSZLkIUOGfO3r61vs6+tb\n7OrqWvPrr7+2MhWT4WuPGjVqnYuLi65Hjx77//Of//QLDQ09AwDBwcF5OTk5HZs2bXrTx8fn+rBh\nwzYp47/55psnw8LCTv7yyy+/HzRo0BZAvyQVEhJyTnndZ599dq2Hh0flff7xEd0TLlWRqkmSJBv+\nolYeA4A33nhjXlJSUurx48fDJ02atMjUEpSpccpSkTFfX99i5d89PDwqy8vLPT09PcsrKioaKY8X\nFRW1NOyzKD/j4eFRafzzhj9nTJZlqUWLFlczMzM1mZmZmqysrMjNmzcPVp5/6KGHLtb350JkSywc\npGrx8fHbd+zY0b+goMA/Ly8veNeuXX2V5y5evPhQu3btTl27dq35unXrRim/0L29vUuuXLnyu7rG\nWfP+AQEBl3U6ncuFCxcCr1692uLrr78eYm0O169f9/nqq6+GVlRUNFq/fv3IAQMGbGvfvv1PAPDl\nl18Ol2VZqqqqcheloU/qx8JBqtayZcui5OTk1V27dv1+1KhR6+Lj47crz82cOfPdgQMHbo2Pj98e\nFxe3W3n82WefXbt27dpnlea48bi6dmbV9fisWbNmJCQkpA8ZMuTr2NhYbV0/a+rnJUmSw8LCTm7e\nvHlwWFjYSUmS5MTExDR3d/eqr776auj8+fNfa9++/U8ajSZz//79Paz+AyKyAV7kkIiIrMIZBxER\nWYWFg4iIrMLCQUREVmHhICIiq7BwEBGRVVg4iIjIKv8fDpFlVFyYoTcAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x52a5c90>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 绘制训练数据量与accuracy的曲线\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "plt.plot(data_num, acc, '-o', linewidth=2.0)\n",
    "plt.xlabel(\"data number\")\n",
    "plt.ylabel(\"accuracy (m)\")\n",
    "plt.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "---\n",
    "\n",
    "## 其他分类器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 导入数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 导入数据\n",
    "import numpy as np\n",
    "import scipy.io as scio\n",
    "offline_data = scio.loadmat('offline_data_random.mat')\n",
    "online_data = scio.loadmat('online_data.mat')\n",
    "offline_location, offline_rss = offline_data['offline_location'], offline_data['offline_rss']\n",
    "trace, rss = online_data['trace'][0:1000, :], online_data['rss'][0:1000, :]\n",
    "del offline_data\n",
    "del online_data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 169,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 定位准确度定义\n",
    "def accuracy(predictions, labels):\n",
    "    return np.mean(np.sqrt(np.sum((predictions - labels + 0.0)**2, 1)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Logistic regression （逻辑斯蒂回归）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "accuracy:  3.08581348591 m\n"
     ]
    }
   ],
   "source": [
    "# 逻辑斯蒂回归是用来分类的\n",
    "labels = np.round(offline_location[:, 0]/100.0) * 100 + np.round(offline_location[:, 1]/100.0)\n",
    "from sklearn.linear_model import LogisticRegressionCV\n",
    "clf_l2_LR_cv = LogisticRegressionCV(Cs=20, penalty='l2', tol=0.001)\n",
    "predict_labels = clf_l2_LR.fit(offline_rss, labels).predict(rss)\n",
    "x = np.floor(predict_labels/100.0)\n",
    "y = predict_labels - x * 100\n",
    "predictions = np.column_stack((x, y)) * 100\n",
    "acc = accuracy(predictions, trace)\n",
    "print \"accuracy: \", acc/100, 'm'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Support Vector Machine for Regression （支持向量机）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 9min 27s\n",
      "Wall time: 12min 42s\n",
      "Wall time: 1.06 s\n",
      "Wall time: 1.05 s\n",
      "accuracy:  2.2468400825 m\n"
     ]
    }
   ],
   "source": [
    "from sklearn import svm\n",
    "clf_x = svm.SVR(C=1000, gamma=0.01)\n",
    "clf_y = svm.SVR(C=1000, gamma=0.01)\n",
    "%time clf_x.fit(offline_rss, offline_location[:, 0])\n",
    "%time clf_y.fit(offline_rss, offline_location[:, 1])\n",
    "%time x = clf_x.predict(rss)\n",
    "%time y = clf_y.predict(rss)\n",
    "predictions = np.column_stack((x, y))\n",
    "acc = accuracy(predictions, trace)\n",
    "print \"accuracy: \", acc/100, \"m\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "#### Support Vector Machine for Classification （支持向量机）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 1min 16s\n",
      "Wall time: 15 s\n",
      "accuracy:  2.50931890608 m\n"
     ]
    }
   ],
   "source": [
    "from sklearn import svm\n",
    "labels = np.round(offline_location[:, 0]/100.0) * 100 + np.round(offline_location[:, 1]/100.0)\n",
    "clf_svc = svm.SVC(C=1000, tol=0.01, gamma=0.001)\n",
    "%time clf_svc.fit(offline_rss, labels)\n",
    "%time predict_labels = clf_svc.predict(rss)\n",
    "x = np.floor(predict_labels/100.0)\n",
    "y = predict_labels - x * 100\n",
    "predictions = np.column_stack((x, y)) * 100\n",
    "acc = accuracy(predictions, trace)\n",
    "print \"accuracy: \", acc/100, 'm'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### random forest regressor （随机森林）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 58.6 s\n",
      "Wall time: 196 ms\n",
      "accuracy:  2.20778352008 m\n"
     ]
    }
   ],
   "source": [
    "from sklearn.ensemble import RandomForestRegressor\n",
    "estimator = RandomForestRegressor(n_estimators=150)\n",
    "%time estimator.fit(offline_rss, offline_location)\n",
    "%time predictions = estimator.predict(rss)\n",
    "acc = accuracy(predictions, trace)\n",
    "print \"accuracy: \", acc/100, 'm'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### random forest classifier （随机森林）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 39.6 s\n",
      "Wall time: 113 ms\n",
      "accuracy:  2.56860790666 m\n"
     ]
    }
   ],
   "source": [
    "from sklearn.ensemble import RandomForestClassifier\n",
    "labels = np.round(offline_location[:, 0]/100.0) * 100 + np.round(offline_location[:, 1]/100.0)\n",
    "estimator = RandomForestClassifier(n_estimators=20, max_features=None, max_depth=20) # 内存受限，tree的数量有点少\n",
    "%time estimator.fit(offline_rss, labels)\n",
    "%time predict_labels = estimator.predict(rss)\n",
    "x = np.floor(predict_labels/100.0)\n",
    "y = predict_labels - x * 100\n",
    "predictions = np.column_stack((x, y)) * 100\n",
    "acc = accuracy(predictions, trace)\n",
    "print \"accuracy: \", acc/100, 'm'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Linear Regression （线性回归）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "accuracy:  3.83239841667 m\n"
     ]
    }
   ],
   "source": [
    "from sklearn.linear_model import LinearRegression\n",
    "predictions = LinearRegression().fit(offline_rss, offline_location).predict(rss)\n",
    "acc = accuracy(predictions, trace)\n",
    "print \"accuracy: \", acc/100, 'm'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Ridge Regression （岭回归）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "accuracy:  3.83255676918 m\n"
     ]
    }
   ],
   "source": [
    "from sklearn.linear_model import RidgeCV\n",
    "clf = RidgeCV(alphas=np.logspace(-4, 4, 10))\n",
    "predictions = clf.fit(offline_rss, offline_location).predict(rss)\n",
    "acc = accuracy(predictions, trace)\n",
    "print \"accuracy: \", acc/100, 'm'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Lasso回归"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "accuracy:  3.83244688001 m\n"
     ]
    }
   ],
   "source": [
    "from sklearn.linear_model import MultiTaskLassoCV\n",
    "clf = MultiTaskLassoCV(alphas=np.logspace(-4, 4, 10))\n",
    "predictions = clf.fit(offline_rss, offline_location).predict(rss)\n",
    "acc = accuracy(predictions, trace)\n",
    "print \"accuracy: \", acc/100, 'm'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Elastic Net （弹性网回归）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "accuracy:  3.832486036 m\n"
     ]
    }
   ],
   "source": [
    "from sklearn.linear_model import MultiTaskElasticNetCV\n",
    "clf = MultiTaskElasticNetCV(alphas=np.logspace(-4, 4, 10))\n",
    "predictions = clf.fit(offline_rss, offline_location).predict(rss)\n",
    "acc = accuracy(predictions, trace)\n",
    "print \"accuracy: \", acc/100, 'm'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Bayesian Ridge Regression （贝叶斯岭回归）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "accuracy:  3.83243319129 m\n"
     ]
    }
   ],
   "source": [
    "from sklearn.linear_model import BayesianRidge\n",
    "from sklearn.multioutput import MultiOutputRegressor\n",
    "clf = MultiOutputRegressor(BayesianRidge())\n",
    "predictions = clf.fit(offline_rss, offline_location).predict(rss)\n",
    "acc = accuracy(predictions, trace)\n",
    "print \"accuracy: \", acc/100, \"m\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "#### Gradient Boosting for regression （梯度提升）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 43.4 s\n",
      "Wall time: 17 ms\n",
      "accuracy:  2.22100945095 m\n"
     ]
    }
   ],
   "source": [
    "from sklearn import ensemble\n",
    "from sklearn.multioutput import MultiOutputRegressor\n",
    "clf = MultiOutputRegressor(ensemble.GradientBoostingRegressor(n_estimators=100, max_depth=10))\n",
    "%time clf.fit(offline_rss, offline_location)\n",
    "%time predictions = clf.predict(rss)\n",
    "acc = accuracy(predictions, trace)\n",
    "print \"accuracy: \", acc/100, \"m\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Multi-layer Perceptron regressor （神经网络多层感知器）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 1min 1s\n",
      "Wall time: 6 ms\n",
      "accuracy:  2.4517504109 m\n"
     ]
    }
   ],
   "source": [
    "from sklearn.neural_network import MLPRegressor\n",
    "clf = MLPRegressor(hidden_layer_sizes=(100, 100))\n",
    "%time clf.fit(offline_rss, offline_location)\n",
    "%time predictions = clf.predict(rss)\n",
    "acc = accuracy(predictions, trace)\n",
    "print \"accuracy: \", acc/100, \"m\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## 目标跟踪"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### KNN + Kalman Filter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "accuracy:  2.24421479398 m\n"
     ]
    }
   ],
   "source": [
    "# knn回归\n",
    "from sklearn import neighbors\n",
    "knn_reg = neighbors.KNeighborsRegressor(40, weights='uniform', metric='euclidean')\n",
    "knn_reg.fit(offline_rss, offline_location)\n",
    "knn_predictions = knn_reg.predict(rss)\n",
    "acc = accuracy(knn_predictions, trace)\n",
    "print \"accuracy: \", acc/100, \"m\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# 对knn定位结果进行卡尔曼滤波\n",
    "\n",
    "from filterpy.kalman import KalmanFilter\n",
    "from scipy.linalg import block_diag\n",
    "from filterpy.common import Q_discrete_white_noise\n",
    "def kalman_tracker():\n",
    "    tracker = KalmanFilter(dim_x=4, dim_z=2)\n",
    "    dt = 1.\n",
    "    # 状态转移矩阵\n",
    "    tracker.F = np.array([[1, dt, 0,  0], \n",
    "                          [0,  1, 0,  0],\n",
    "                          [0,  0, 1, dt],\n",
    "                          [0,  0, 0,  1]])\n",
    "    # 用filterpy计算Q矩阵\n",
    "    q = Q_discrete_white_noise(dim=2, dt=dt, var=0.001)\n",
    "    # tracker.Q = block_diag(q, q)\n",
    "    tracker.Q = np.eye(4) * 0.01\n",
    "    # tracker.B = 0\n",
    "    # 观测矩阵\n",
    "    tracker.H = np.array([[1., 0, 0, 0],\n",
    "                          [0, 0, 1., 0]])\n",
    "    # R矩阵\n",
    "    tracker.R = np.array([[4., 0],\n",
    "                          [0, 4.]])\n",
    "    # 初始状态和初始P\n",
    "    tracker.x = np.array([[7.4, 0, 3.3, 0]]).T \n",
    "    tracker.P = np.zeros([4, 4])\n",
    "    return tracker"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "accuracy:  1.76116239607 m\n"
     ]
    }
   ],
   "source": [
    "tracker = kalman_tracker()\n",
    "zs = np.array([np.array([i]).T / 100. for i in knn_predictions]) # 除以100，单位为m\n",
    "mu, cov, _, _ = tracker.batch_filter(zs) # 这个函数对一串观测值滤波\n",
    "knn_kf_predictions = mu[:, [0, 2], :].reshape(1000, 2)\n",
    "acc = accuracy(knn_kf_predictions, trace / 100.)\n",
    "print \"accuracy: \", acc, \"m\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### KNN + Particle Filter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "accuracy:  2.24421479398 m\n"
     ]
    }
   ],
   "source": [
    "# knn回归\n",
    "from sklearn import neighbors\n",
    "knn_reg = neighbors.KNeighborsRegressor(40, weights='uniform', metric='euclidean')\n",
    "knn_reg.fit(offline_rss, offline_location)\n",
    "knn_predictions = knn_reg.predict(rss)\n",
    "acc = accuracy(knn_predictions, trace)\n",
    "print \"accuracy: \", acc/100, \"m\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# 设计粒子滤波中各个步骤的具体实现\n",
    "\n",
    "from numpy.random import uniform, randn, random, seed\n",
    "from filterpy.monte_carlo import multinomial_resample\n",
    "import scipy.stats\n",
    "seed(7)\n",
    "\n",
    "def create_particles(x_range, y_range, v_mean, v_std, N):\n",
    "    \"\"\"这里的粒子状态设置为（坐标x，坐标y，运动方向，运动速度）\"\"\"\n",
    "    particles = np.empty((N, 4))\n",
    "    particles[:, 0] = uniform(x_range[0], x_range[1], size=N)\n",
    "    particles[:, 1] = uniform(y_range[0], y_range[1], size=N)\n",
    "    particles[:, 2] = uniform(0, 2 * np.pi, size=N)\n",
    "    particles[:, 3] = v_mean + (randn(N) * v_std)\n",
    "    return particles\n",
    "\n",
    "def predict_particles(particles, std_heading, std_v, x_range, y_range):\n",
    "    \"\"\"这里的预测规则设置为：粒子根据各自的速度和方向（加噪声）进行运动，如果超出边界则随机改变方向再次尝试，\"\"\"\n",
    "    idx = np.array([True] * len(particles))\n",
    "    particles_last = np.copy(particles)\n",
    "    for i in range(100): # 最多尝试100次\n",
    "        if i == 0:\n",
    "            particles[idx, 2] = particles_last[idx, 2] + (randn(np.sum(idx)) * std_heading)\n",
    "        else:\n",
    "            particles[idx, 2] = uniform(0, 2 * np.pi, size=np.sum(idx)) # 随机改变方向\n",
    "        particles[idx, 3] = particles_last[idx, 3] + (randn(np.sum(idx)) * std_v)\n",
    "        particles[idx, 0] = particles_last[idx, 0] + np.cos(particles[idx, 2] ) * particles[idx, 3]\n",
    "        particles[idx, 1] = particles_last[idx, 1] + np.sin(particles[idx, 2] ) * particles[idx, 3]\n",
    "        # 判断超出边界的粒子\n",
    "        idx = ((particles[:, 0] < x_range[0])\n",
    "                | (particles[:, 0] > x_range[1])\n",
    "                | (particles[:, 1] < y_range[0]) \n",
    "                | (particles[:, 1] > y_range[1]))\n",
    "        if np.sum(idx) == 0:\n",
    "            break\n",
    "            \n",
    "def update_particles(particles, weights, z, d_std):\n",
    "    \"\"\"粒子更新，根据观测结果中得到的位置pdf信息来更新权重，这里简单地假设是真实位置到观测位置的距离为高斯分布\"\"\"\n",
    "    # weights.fill(1.)\n",
    "    distances = np.linalg.norm(particles[:, 0:2] - z, axis=1)\n",
    "    weights *= scipy.stats.norm(0, d_std).pdf(distances)\n",
    "    weights += 1.e-300\n",
    "    weights /= sum(weights)\n",
    "\n",
    "def estimate(particles, weights):\n",
    "    \"\"\"估计位置\"\"\"\n",
    "    return np.average(particles, weights=weights, axis=0)\n",
    "\n",
    "def neff(weights):\n",
    "    \"\"\"用来判断当前要不要进行重采样\"\"\"\n",
    "    return 1. / np.sum(np.square(weights))\n",
    "\n",
    "def resample_from_index(particles, weights, indexes):\n",
    "    \"\"\"根据指定的样本进行重采样\"\"\"\n",
    "    particles[:] = particles[indexes]\n",
    "    weights[:] = weights[indexes]\n",
    "    weights /= np.sum(weights)\n",
    "    \n",
    "def run_pf(particles, weights, z, x_range, y_range):\n",
    "    \"\"\"迭代一次粒子滤波，返回状态估计\"\"\"\n",
    "    x_range, y_range = [0, 20], [0, 15]\n",
    "    predict_particles(particles, 0.5, 0.01, x_range, y_range) # 1. 预测\n",
    "    update_particles(particles, weights, z, 4) # 2. 更新\n",
    "    if neff(weights) < len(particles) / 2: # 3. 重采样\n",
    "        indexes = multinomial_resample(weights)\n",
    "        resample_from_index(particles, weights, indexes)\n",
    "    return estimate(particles, weights) # 4. 状态估计"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "final state:  [  8.16137026  12.49569879   4.06952385   0.54954716]\n",
      "accuracy:  1.80881825483 m\n"
     ]
    }
   ],
   "source": [
    "# 对knn定位结果进行粒子滤波\n",
    "\n",
    "knn_pf_predictions = np.empty(knn_predictions.shape)\n",
    "x_range, y_range = [0, 20], [0, 15]\n",
    "n_particles = 50000\n",
    "particles = create_particles(x_range, y_range, 0.6, 0.01, n_particles) # 初始化粒子\n",
    "weights = np.ones(n_particles) / n_particles # 初始化权重\n",
    "\n",
    "for i, pos in enumerate(knn_predictions):\n",
    "    pos = pos.copy() / 100.\n",
    "    state = run_pf(particles, weights, pos, x_range, y_range)\n",
    "    knn_pf_predictions[i, :] = state[0:2]\n",
    "\n",
    "acc = accuracy(knn_pf_predictions, trace / 100.)\n",
    "print \"final state: \", state\n",
    "print \"accuracy: \", acc, \"m\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x72e7df0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "x_i = range(220, 280)\n",
    "tr, = plt.plot(trace[x_i, 0] / 100., trace[x_i, 1] / 100., 'k-', linewidth=3)\n",
    "pf, = plt.plot(knn_pf_predictions[x_i, 0], knn_pf_predictions[x_i, 1], 'r-')\n",
    "kf, = plt.plot(knn_kf_predictions[x_i, 0], knn_kf_predictions[x_i, 1], 'b-')\n",
    "knn_ = plt.scatter(knn_predictions[x_i, 0] / 100., knn_predictions[x_i, 1] / 100.)\n",
    "plt.xlabel('x (m)')\n",
    "plt.ylabel('y (m)')\n",
    "plt.legend([tr, pf, kf, knn_], [\"real trace\", \"pf\", \"kf\", \"knn\"])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
